package com.clx.channelHandler.hander;

import com.clx.compress.CompressWrapper;
import com.clx.compress.Compressor;
import com.clx.compress.CompressorFactory;
import com.clx.enumeration.RequestType;
import com.clx.serialize.Serializer;
import com.clx.serialize.SerializerFactory;
import com.clx.serialize.SerializerWrapper;
import com.clx.transport.message.CrpcRequest;
import com.clx.transport.message.MessageFormatConstant;
import com.clx.transport.message.RequestPayload;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import lombok.extern.slf4j.Slf4j;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.Date;
import java.util.Random;

/**
 * 基于长度字段的帧解码器
 * */
@Slf4j
public class CrpcRequestDecoder extends LengthFieldBasedFrameDecoder {
    public CrpcRequestDecoder() {
        super(
                // 找到当前报文的总长度，截取报文，截取出来的报文我们可以去进行解析
                // 最大帧的长度，超过这个maxFrameLength值会直接丢弃
                MessageFormatConstant.MAX_FRAME_LENGTH,
                // 长度字段的偏移量
                MessageFormatConstant.MAGIC.length + MessageFormatConstant.VERSION_LENGHT + MessageFormatConstant.HEADER_FIELD_LENGTH,
                // 长度字段的长度
                MessageFormatConstant.FULL_FIELD_LENGTH,
                // todo 负载的适配长度
                -(MessageFormatConstant.MAGIC.length + MessageFormatConstant.VERSION_LENGHT + MessageFormatConstant.HEADER_FIELD_LENGTH + MessageFormatConstant.FULL_FIELD_LENGTH),
                0);
    }

    @Override
    protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
        Thread.sleep(new Random().nextInt(50));

        try {
            Object decode = super.decode(ctx, in);
            if (decode instanceof ByteBuf) {
                ByteBuf byteBuf = (ByteBuf) decode;
                return decodeFrame(byteBuf);
            }
            return null;
        } catch (RuntimeException e) {
            // 记录异常与非法请求的字节内容，便于排查
            log.error("解码请求时发现非法类型，请求字节内容：{}",
                    in.toString(io.netty.util.CharsetUtil.UTF_8), e);
            // 关闭连接（非法请求无法继续处理，避免资源浪费）
            ctx.close();
            return null;
        }
    }

    private Object decodeFrame(ByteBuf byteBuf) {
        // ========== 1. 魔数读取校验 ==========
        if (byteBuf.readableBytes() < MessageFormatConstant.MAGIC.length) {
            throw new RuntimeException("魔数字节不足，预期：" + MessageFormatConstant.MAGIC.length + "，实际可读：" + byteBuf.readableBytes());
        }
        byte[] magic = new byte[MessageFormatConstant.MAGIC.length];
        byteBuf.readBytes(magic);
        // 魔数匹配校验
        for (int i = 0; i < magic.length; i++) {
            if (magic[i] != MessageFormatConstant.MAGIC[i]){
                throw new RuntimeException("请求魔数不合法，非法请求");
            }
        }

        // ========== 2. 版本号读取校验（1字节） ==========
        if (byteBuf.readableBytes() < 1) {
            throw new RuntimeException("版本号字节不足，非法请求");
        }
        byte version = byteBuf.readByte();
        if (version > MessageFormatConstant.VERSION){
            throw new RuntimeException("请求版本不支持，当前支持版本：" + MessageFormatConstant.VERSION);
        }

        // ========== 3. 头部长度读取校验（short，2字节） ==========
        if (byteBuf.readableBytes() < 2) {
            throw new RuntimeException("头部长度字节不足，非法请求");
        }
        short headLength = byteBuf.readShort();

        // ========== 4. 总长度读取校验（int，4字节） ==========
        if (byteBuf.readableBytes() < 4) {
            throw new RuntimeException("总长度字节不足，非法请求");
        }
        int fullLength = byteBuf.readInt();

        // ========== 5. 头部字段（请求类型、序列化类型等）读取校验（共 1+1+1+8=11 字节） ==========
        if (byteBuf.readableBytes() < 11) {
            throw new RuntimeException("请求头部字段字节不足，非法请求");
        }

        // 5，请求类型,
        byte requestType = byteBuf.readByte();
        // 6，序列化类型
        byte serializeTypeType = byteBuf.readByte();
        // 7，压缩类型
        byte compressType = byteBuf.readByte();
        // 8，请求id
        long requestId = byteBuf.readLong();

        // 9，时间戳
        long timeStamp = byteBuf.readLong();

        //我们需要封装
        CrpcRequest crpcRequest = new CrpcRequest();
        crpcRequest.setRequestType(requestType);
        crpcRequest.setCompressType(compressType);
        crpcRequest.setSerializeType(serializeTypeType);
        crpcRequest.setRequestId(requestId);
        crpcRequest.setTimeStamp(timeStamp);

        // todo 心跳请求没有负载，此处可以判断并直接返回
        if (requestType == RequestType.HEART_BEAT.getId()){
            return crpcRequest;
        }

        int payloadLength = fullLength - headLength;
        byte[] payload = new byte[payloadLength];
        byteBuf.readBytes(payload);

        // 有了字节数组之后就可以减压缩反序列化
        // 1.解压缩
        if (payload != null && payload.length != 0) {
            Compressor compressor = CompressorFactory.getCompressor(compressType).getCompressor();
            payload = compressor.decompress(payload);


            // 2.反序列化
            // 1 --> jdk
            Serializer serializer = SerializerFactory.getSerialze(serializeTypeType).getSerializer();
            RequestPayload requestPayload = serializer.deserialize(payload, RequestPayload.class);
            crpcRequest.setRequestPayload(requestPayload);
        }


        if (log.isDebugEnabled()){
            log.debug("请求【{}】已经在服务端完成解码工作。",crpcRequest.getRequestId());
        }
        return crpcRequest;
    }
}
